import * as vscode from 'vscode'
import {twsManager} from './TwsManager';
import {getAssignments, getProgramsTopicsTasks} from './contstants/vscode-request';
import * as path from "path";
import QuizType from './contstants/quiz-type'
import {
	SIGIN,
	SUBMIT_SINGLE_LANGUAGE_CODING_WITH_TREE_BTN,
	TO_ASSIGNMENT_DETAIL,
	TO_PROGRAM_DETAIL,
	TO_TASK_DETAIL
} from './contstants/Commands';

class ProgramMenusProvider implements vscode.TreeDataProvider<Dependency> {
	private context?: vscode.ExtensionContext | any;
	private _onDidChangeTreeData: vscode.EventEmitter<Dependency | undefined> = new vscode.EventEmitter<Dependency | undefined>();
	readonly onDidChangeTreeData: vscode.Event<Dependency | undefined> = this._onDidChangeTreeData.event;
	private userProgramsMenu: UserPrograms = new UserPrograms([], [], [])
	private assignmentsMenu: Assignment = new Assignment([])
	private currentMenuType: string = 'userProgramsMenu'
	public initialize(context: vscode.ExtensionContext): void {
		this.context = context;
	}

	async refresh() {
		if (!twsManager.isLogin()) {
			this._onDidChangeTreeData.fire();
			return
		}
		const { jwt, sessionId } = twsManager.getUser()
		const { programs, topics, tasks } = await getProgramsTopicsTasks(jwt, sessionId)
		this.userProgramsMenu = new UserPrograms(programs, topics, tasks)
		this.changeCurrentType('userProgramsMenu')
	}

	async refreshAssignmentsMenus(task: any) {
		const { jwt, sessionId } = twsManager.getUser()
		let assignments = await getAssignments(task.id, jwt, sessionId)
		assignments = assignments.map((item: any) => {
			return {
				...item, programId: task.programId, taskTitle: task.title,
				taskId: task.id, quizId: item.selectedQuizzes[0].quizId
			}
		})
		this.assignmentsMenu = await new Assignment(assignments)
		this.changeCurrentType('assignmentsMenu')
	}
	changeCurrentType(type: string) {
		this.currentMenuType = type
		this._onDidChangeTreeData.fire();
	}
	getTreeItem(element: Dependency): vscode.TreeItem {
		if (!element) {
			return element
		}
		return {
			...element,
			description: element.description,
			iconPath: this.context.asAbsolutePath(path.join("media", `${element.icon}`))
		}
	}

	getChildren(element?: Dependency): Thenable<Dependency[]> {
		if (!twsManager.isLogin()) {
			return Promise.resolve([
				new Dependency('Click to sign in', '', vscode.TreeItemCollapsibleState.None, 'login.svg', '', '',
					{
						command: SIGIN,
						title: 'click to sign in'
					})
			]);

		}
		if (this.currentMenuType === 'userProgramsMenu') {
			if (!element) {
				return Promise.resolve(this.userProgramsMenu.getPrograms());
			}
			if (element.type === 'program') {
				vscode.commands.executeCommand(TO_PROGRAM_DETAIL, element.item)
				return Promise.resolve(this.userProgramsMenu.findTopicsByProgramId(element.item.id));
			}
			if (element.type === 'topic') {
				return Promise.resolve(this.userProgramsMenu.findTasksByTopicId(element.item.id));
			}
		}
		if (this.currentMenuType === 'assignmentsMenu') {
			if (!element) {
				return Promise.resolve(this.assignmentsMenu.getAssignments());
			}
			if (element.type === 'back') {
				this.changeCurrentType('userProgramsMenu')
				return Promise.resolve([]);
			}
			return Promise.resolve(this.assignmentsMenu.getAssignmentTool(element.item));
		}

		return Promise.resolve([]);
	}

}

export class Dependency extends vscode.TreeItem {

	constructor(
		public readonly label: string,
		private progress: string,
		public readonly collapsibleState: vscode.TreeItemCollapsibleState,
		public readonly icon: string,
		public readonly item?: any,
		public readonly type?: string,
		public readonly command?: vscode.Command

	) {
		super(label, collapsibleState);
	}

	get description(): string {
		return this.progress;
	}
}

class UserPrograms {
	constructor(
		private readonly programs: any[],
		private readonly topics: Array<any>,
		private readonly tasks: Array<any>) { }

	findTopicsByProgramId(programId: number): Array<any> {
		return this.topics.filter(topic => topic.programId === programId)
			.map(dep => {
				const childCount = this.tasks.filter(task => task.topicId === dep.id).length
				return new Dependency(dep.title, childCount + '',
					vscode.TreeItemCollapsibleState.Collapsed, 'topic.svg', dep, 'topic')
			}
			)
	}

	findTasksByTopicId(topicId: number): Array<any> {
		return this.tasks.filter(task => task.topicId === topicId)
			.map(dep =>
				new Dependency(dep.title, dep.assignments.length + '',
					vscode.TreeItemCollapsibleState.Collapsed, 'task.svg', dep, 'task',
					{
						command: TO_TASK_DETAIL,
						title: '任务卡详情',
						arguments: [dep]
					})
			)
	}

	getPrograms(): Array<any> {
		return this.programs.map(dep => {
			const childCount = this.topics.filter(topic => topic.programId === dep.id).length
			return new Dependency(dep.title, childCount + '',
				vscode.TreeItemCollapsibleState.Collapsed, 'program.svg', dep, 'program')
		})

	}
}
class Assignment {
	constructor(private readonly assignments: any[]) { }

	getAssignments(): Array<any> {
		let result = this.assignments
			.filter(item => item.type !== 'HOMEWORK_QUIZ')
			.map(dep => {
				return new Dependency(`${dep.title}「${QuizType[dep.type].text}」`,
					'',
					vscode.TreeItemCollapsibleState.Expanded,
					dep.isFinished ? 'finish.svg' : 'progress.svg', dep, 'assignment')
			})
		result.unshift(new Dependency('返回任务卡列表', '',
			vscode.TreeItemCollapsibleState.Collapsed, 'back.svg', '', 'back'))
		return result
	}

	getAssignmentTool(item: any): Array<any> {
		const { isStart } = item
		const result = [
			new Dependency(isStart ? '继续学习' : '开始学习', '',
				vscode.TreeItemCollapsibleState.None,
				'iconPath', '', '', {
					command: TO_ASSIGNMENT_DETAIL,
					title: '作业详情',
					arguments: [item]
				})
		]
		if (item.type === 'ONLINE_LANGUAGE_QUIZ') {
			result.push(new Dependency(`提交作业`, '',
				vscode.TreeItemCollapsibleState.None,
				'iconPath', '', '',
				{
					command: SUBMIT_SINGLE_LANGUAGE_CODING_WITH_TREE_BTN,
					title: 'Submit',
					arguments: [item]
				})
			)
		}
		return result
	}

}
export const programMenusProvider = new ProgramMenusProvider()